#include <reg51.h>
#include <string.h>
//******************************************* PROMENLJIVE *********************************************************************//
//VREME
short xdata msec;
char xdata sec;
char xdata min;
char xdata sati;
bit vreme_podeseno;
char code nepodeseno_vreme[8]={'S','E','T',' ','T','I','M','E'}; 


//promenljiva za TIMER1
bit oneMS=0;

//PORTOVI
sbit LE_DISPL = P1^0;
sbit LE_START = P1^1;
sbit LE_MONEY_OUT = P1^2;
sbit SEL_moneyD0_KD0 = P1^3;

sbit moneyD0_KD0 = P1^4;
sbit moneyD1_KD1 = P1^5;
sbit moneyD2_KD2 = P1^6;
sbit KD3 = P1^7;

//ZARADA
short xdata ukupno_zaradjeno;

//STATUSI
bit kupljen_proizvod;
bit pokrenut_motor;

//VEZANO ZA VRACANJE KUSURA
char novcanica;
bit nema_novcanice200 = 0;
bit nema_novcanice100 = 0;
bit nema_novcanice50 = 0;
bit nema_novcanice20 = 0;
bit nema_novcanice10 = 0;
bit nema_novcanica = 0;
bit novcanica_izbacena = 0;

//VEZANO ZA PROIZVODE
char xdata nazivi_proizvoda[100][16];
char xdata cene_proizvoda[100];
short xdata zarade_proizvoda[100];

//VEZANO ZA UNOS SA TASTATURE
char uneto_cifara;
char cifra1;
char cifra2;
char code tasteri[13]={'0','3','6','9','1','4','7','o','2','5','8','c','k'};   // o - enter  c - del k - kusur
char data taster;

//VEANO ZA DISPLEJ
char trenutni_ispis[8];
char trenutno_vreme[8];
char trenutna_poruka[8];
char prikazuj_vreme_ispis_poruku;
char trenutni_karakter;
char trenutni_simbol;



//VEZANO ZA UNOS NOVCA
short suma;					//trenutna suma nova koja sa ispisuje na ukranu 

//KOPIJA MASKE ZA PREKIDE U MEMORIJI
char MASKA;

//VEZANO ZA ISPIS NA DISPLEJU
char kodovi[8];
char brojac;


//vezano za stanja za serijski port
char trenutno_stanje;
char broj_proizvoda;
char broj_poruke;
char Lpromet;
char Hpromet;


//****************************************** KONSTANTE **********************************************************************//


#define BR0H 0xFC;      // "-922" da se broji svakih 922x12/11.059 = 1.0 ms
#define BR0L 0x66;		// -992 = 1111 1100 0110 0110b = FC66
#define POSTAVI_CENU 0x01
#define POSTAVI_NAZIV_CENU 0x02
#define PROCITAJ_PROMET_P 0x03
#define RESETUJ_PROMET_P 0x04
#define PROCITAJ_PROMET_U 0x05
#define RESETUJ_PROMET_U 0x06
#define PROMET_P 0x07
#define PROMET_U 0x08
#define PODESAVANJE_VREMENA 0x09
#define STARTNO_STANJE 0x0A



//******************************************************** GLAVNI PROGRAM ****************************************************//

void main ( void ) using 0 {

	vreme_podeseno = 0;				//da li je vreme podeseno ili ne
	ukupno_zaradjeno = 0;  			//suma novca koja je zaradjena
	uneto_cifara = 0;				//broj cifara koje su unete sa tastature
	prikazuj_vreme_ispis_poruku = 0;				//da li da timer ispisuje vreme za displej
	trenutno_stanje = STARTNO_STANJE;

 	P2=0x00;						//pocetne vrednosti za portove
	P0=0x00;

	LE_START = 1;
	LE_START = 0;

	LE_MONEY_OUT = 1;
	LE_MONEY_OUT = 0;
	
	TH0 = BR0H;//brojac 0
	TL0 = BR0L;

	TH1 = 0xFC;//brojac 1
	TL1 = 0x66;
	
	TCON = 0x11;// 0001 0001 - brojac 0 se startuje(01) , brojac 1 ne(00)
	TMOD = 0x05;// 0001 0001 - brojac 0 16-bit , brojac 1 16-bit

	SCON = 0x90; // 1001 000 -> mode 2, radi na osnovu oscilatora, postavljen je bit kojim se aktivira prijem
	PCON = 0x00; // najvisi bit PCON odredjuje da li se radi clk/32 ili clk/64, ovde je 64

	IE = 0xF6;	//zabranjuje se prekid sa tastature i sa brojaca 1ms od trenutka startovaja 

	while(1){}
}

void pokreni_timer (void) {
	TH1 = BR0H; // setuju se startne vrednosti brojaca, za brojanje 1 ms
	TL1 = BR0L;
	TR1 = 1;
}

void cekaj_1msec(){
	MASKA = IE;

	IE = 0xE8;//dozvoli prekid od T1
	pokreni_timer();
	while(oneMS!=1){}//cekaj 1ms
	oneMS=0;
	TR1 = 0;//stopiraj T1

	IE = MASKA;
}


void ucitaj_taster(void){
	SEL_moneyD0_KD0 = 0;   									// 1-selektuje aparat za pare, 0-selektuje tastaturu
	taster = P1 & 0x0F;										// procitaj vrednost sa porta 
	taster = tasteri[taster];								//prevedi vrednost tastera u odgovarajuci char

	if(uneto_cifara  == 0) cifra1 = taster;
	else cifra2 = taster;
}

void formiraj_ispis(void){
	if(uneto_cifara ==2 ){
		trenutni_ispis[0] = cifra1;
		trenutni_ispis[1] = cifra2;
	}
	else if (uneto_cifara == 1){
		trenutni_ispis[0] = cifra1;
		trenutni_ispis[1] = 32;  // kod praznog displeja
	}
	else{
		trenutni_ispis[0] = 32;
		trenutni_ispis[1] = 32;
	}

	trenutni_ispis[7]=suma%10;
	trenutni_ispis[6]=((suma-trenutni_ispis[7])%100)/10;
	trenutni_ispis[5]=((suma-trenutni_ispis[7]-trenutni_ispis[6])%1000)/100;
	trenutni_ispis[4]=(suma-trenutni_ispis[7]-trenutni_ispis[6]-trenutni_ispis[5])/1000;

	if(trenutni_ispis[4]==0){
		trenutni_ispis[4]=32;
		if(trenutni_ispis[5]==0){
			trenutni_ispis[5]=32;
		}
	}	
}

void formiraj_vreme(){
	if(vreme_podeseno == 1){
		trenutno_vreme[1]=sati%10;	
		trenutno_vreme[0]=(sati-trenutno_vreme[1])/10;
		trenutno_vreme[2]=58;
		trenutno_vreme[4]=min%10;	
		trenutno_vreme[3]=(min-trenutno_vreme[4])/10;
		trenutno_vreme[5]=58;
		trenutno_vreme[7]=sec%10;	
		trenutno_vreme[6]=(sec-trenutno_vreme[7])/10;
	}
	else{ 
	trenutno_vreme[0] = nepodeseno_vreme[0];
	trenutno_vreme[1] = nepodeseno_vreme[1];
	trenutno_vreme[2] = nepodeseno_vreme[2];
	trenutno_vreme[3] = nepodeseno_vreme[3];
	trenutno_vreme[4] = nepodeseno_vreme[4];
	trenutno_vreme[5] = nepodeseno_vreme[5];
	trenutno_vreme[6] = nepodeseno_vreme[6];
	trenutno_vreme[7] = nepodeseno_vreme[7];
	}
}

void izbaci_novcanicu(char novcanica){
	char temp = novcanica * 4;
	P2 = temp + 2;											//novcanica + write
	LE_MONEY_OUT = 1;
	cekaj_1msec();
	LE_MONEY_OUT = 0;
}


void procitaj_vrednost_iz_automata(void){
	P2 = 1;													//read
	LE_MONEY_OUT = 1;
	cekaj_1msec();
	LE_MONEY_OUT = 0;
	SEL_moneyD0_KD0 = 1;
	if(P1^4==1 && P1^5==0 && P1^6==0){suma += 10;}
	else if(P1^4==0 && P1^5==1 && P1^6==0){suma += 20;}
	else if(P1^4==1 && P1^5==1 && P1^6==0){suma += 50;}
	else if(P1^4==0 && P1^5==0 && P1^6==1){suma += 100;}
	else if(P1^4==0 && P1^5==0 && P1^6==1){suma += 200;}

	else if(P1^4==0 && P1^5==0 && P1^6==0){nema_novcanica = 1;}
	else if(P1^4==1 && P1^5==1 && P1^6==1){novcanica_izbacena = 1;}

	P2 = 0;													//ukida se signal read
	LE_MONEY_OUT = 1;
	LE_MONEY_OUT = 0;
}

void ispisi_poruku_na_displeju(char poruka[]){
	char temp = prikazuj_vreme_ispis_poruku;
	char temp_sec;
	char i = 0;
	char j = 0;
	char temp_poruka[8]={' ',' ',' ',' ',' ',' ',' ',' '};
	char len = sizeof(poruka);
	prikazuj_vreme_ispis_poruku = 2;

	for(i=0;i<len+9;i++){	
		trenutna_poruka[0] = temp_poruka[0];
		trenutna_poruka[1] = temp_poruka[1];
		trenutna_poruka[2] = temp_poruka[2];
		trenutna_poruka[3] = temp_poruka[3];
		trenutna_poruka[4] = temp_poruka[4];
		trenutna_poruka[5] = temp_poruka[5];
		trenutna_poruka[6] = temp_poruka[6];
		trenutna_poruka[7] = temp_poruka[7];
		temp_sec=sec;while(temp_sec==sec){}
		//shiftovanje poruke
		for(j=0;j<7;j++){
			temp_poruka[j] = temp_poruka[j+1];
		}
		temp_poruka[7]=(i<len)? poruka[i]:' ';	
	}

	prikazuj_vreme_ispis_poruku = temp;
}

//------------------------------------------- VRACANJE KUSURA -------------------------------------------
void vrati_kusur(){
	while(1){
		if(suma>=200 && nema_novcanice200 == 0){
			novcanica = 200;
			izbaci_novcanicu(novcanica);
			cekaj_1msec();//cekaj 1ms
			procitaj_vrednost_iz_automata();
			if(nema_novcanica == 1)nema_novcanice200 = 1;
			nema_novcanica = 0;
		}
		else if(suma>=100 && nema_novcanice100 == 0){
			novcanica = 100;
			izbaci_novcanicu(novcanica);
			cekaj_1msec();//cekaj 1ms
			procitaj_vrednost_iz_automata();
			if(nema_novcanica == 1)nema_novcanice100 = 1;
			nema_novcanica = 0;
		}
		else if(suma>=50 && nema_novcanice50 == 0){
			novcanica = 50;
			izbaci_novcanicu(novcanica);
			cekaj_1msec();//cekaj 1ms
			procitaj_vrednost_iz_automata();
			if(nema_novcanica == 1)nema_novcanice50 = 1;
			nema_novcanica = 0;
		}
		else if(suma>=20 && nema_novcanice20 == 0){
			novcanica = 20;
			izbaci_novcanicu(novcanica);
			cekaj_1msec();//cekaj 1ms
			procitaj_vrednost_iz_automata();
			if(nema_novcanica == 1)nema_novcanice20 = 1;
			nema_novcanica = 0;
		}
		else if(suma>=10 && nema_novcanice10 == 0){
			novcanica = 10;
			izbaci_novcanicu(novcanica);	
			cekaj_1msec();//cekaj 1ms
			procitaj_vrednost_iz_automata();
			if(nema_novcanica == 1){
				ispisi_poruku_na_displeju("NESTALO NOVCANICA");//posalji na disp nestalo novcanica			
				break;
			}
		}
		else if(suma==0)
			ispisi_poruku_na_displeju("HVALA STO STE KORISTILI NAS AUTOMAT");
			break;		
	}
	nema_novcanice200=0;nema_novcanice100=0;nema_novcanice50=0;nema_novcanice20=0;nema_novcanice10=0;//vrati indikatore na 0
}
 
void prikazi_poruku_o_proizvodu(){
	if(cene_proizvoda[cifra1 * 10 + cifra2] < suma)	ispisi_poruku_na_displeju(strcat(nazivi_proizvoda[cifra1 * 10 + cifra2] ," ENTER = yes/DEL = no"));	
	else ispisi_poruku_na_displeju("NISTE UNELI DOVOLJNO NOVCA");

}

void na_pocetno_stanje(){
	kupljen_proizvod = 0;
	uneto_cifara = 0;
	prikazuj_vreme_ispis_poruku = 0;
	nema_novcanica = 0;
	trenutno_stanje = STARTNO_STANJE;
	IE = 0xF6;
}

//***************************************************************** PREIDNE RUTINE ************************************************************

void timer0_1ms_prekid(void) large interrupt 1{  // prekid od tajmera 0 - brojaca vremena
	MASKA = IE;					//kopira IE u memoriju
	IE = 0x00;					//zabranjuje sve prekide
	if(++msec==1000){
		msec=0;
		sec++;
		if(sec==60){
			sec=0;
			min++;
			if(min==60){
				min=0;
				sati++;
				if(sati==24){
					sati=0;
				}
			}
		}
	}
	formiraj_vreme();
	
	trenutni_karakter = (trenutni_karakter + 1)%8;
	P0 = trenutni_karakter;
	if (prikazuj_vreme_ispis_poruku == 0)P2 = trenutno_vreme[trenutni_karakter];
    else if (prikazuj_vreme_ispis_poruku == 1)P2 = trenutni_ispis[trenutni_karakter];
	else P2 = trenutna_poruka[trenutni_karakter];
	P2 = trenutno_vreme[trenutni_karakter];
	LE_DISPL = 1;
	LE_DISPL = 0;	

	pokreni_timer();
	IE = MASKA;				//kopira zapamcenu masku u IE
}

void timer1_1ms_posle_startovanja(void) large interrupt 3{
	MASKA = IE;					//kopira IE u memoriju
	IE = 0x00;					//zabranjuje sve prekide
	oneMS=1;
	IE = MASKA;	
}

void extern1_automat_spirala(void) large interrupt 2{
	MASKA = IE;					//kopira IE u memoriju
	IE = 0xE6;					//zabranjuje prekide od tastature
	procitaj_vrednost_iz_automata();
	if (pokrenut_motor == 1){
		kupljen_proizvod = 1;
		pokrenut_motor = 0;
		P0 = 0;
		LE_START = '1';
		LE_START = '0';
	}
	IE = MASKA;										
}

void extern0_tastatura(void) large reentrant interrupt 0{
	MASKA = IE;												//kopira IE u memoriju
	IE = 0xE6;												//zabranjuje prekide od tastature
	ucitaj_taster();

	switch(taster){

		case 'c': 									// pritisnut je taster "del"
			if(uneto_cifara > 0){
				if(uneto_cifara == 1){cifra1 = ' ';}
				if(uneto_cifara == 2){cifra2 = ' ';}
				uneto_cifara--;
				IE = MASKA;
			}		
		break;

		case 'o':														// pritisnut je taster "enter"
			if(uneto_cifara == 2){
				if(cene_proizvoda[cifra1 * 10 + cifra2] < suma){
					char temp_sec;
					P0 = cifra1 * 10 + cifra2;
					LE_START = '1';
					LE_START = '0';
					pokrenut_motor = 1;
					temp_sec = sec + 6;while(temp_sec>=sec){}
					if(kupljen_proizvod){
						suma-=cene_proizvoda[cifra1 * 10 + cifra2];
						zarade_proizvoda[cifra1 * 10 + cifra2]+= cene_proizvoda[cifra1 * 10 + cifra2];
						if(suma == 0){
							ispisi_poruku_na_displeju("HVALA STO STE KORISTILI NAS AUTOMAT");
							na_pocetno_stanje();
						}
						else {
							ispisi_poruku_na_displeju("PRITISNITE TASTER ZA KUSUR");
							IE = MASKA;
						}
					}
					else {
						ispisi_poruku_na_displeju("NESTALO IZABERITE DRUGI PROIZVOD");
						IE = MASKA;
					}
				}
			}
		break;

		case 'k':                                   // pritisnut taster "kusur"
			if (kupljen_proizvod && (suma <= 200)){	
				vrati_kusur();
				na_pocetno_stanje();
	        	}	
		break;
		default : 									// pritisnut je taster 0..9
				ucitaj_taster();
				formiraj_ispis();
				uneto_cifara += 1;
				if(uneto_cifara == 1)prikazuj_vreme_ispis_poruku = 1;
				else prikazi_poruku_o_proizvodu();
				IE = MASKA;
		break;		
	}
}

void serijski_port(void) large interrupt 4{
	char poruka;
	//RECEIVE
	if (RI == 1) {
		poruka = SBUF;
		if(broj_poruke == 0){
			//RESETUJ UKUPAN PROMET
			if(poruka == RESETUJ_PROMET_U){
				char i;
				for(i=0; i<100; i++)zarade_proizvoda[i]=0;
			}
			//PROCITAJ UKUPAN PPROMET
			else if(poruka == PROCITAJ_PROMET_U){
				char i=0;
				short promet_u=0;
				for(i=0;i<100;i++)promet_u += zarade_proizvoda[i];
				Lpromet = promet_u & 0x00FF;
				Hpromet = promet_u >> 8;
				SBUF=Lpromet;
			}
			broj_poruke++;
			trenutno_stanje = poruka;
		}
		else{
			switch(trenutno_stanje){
				//POSTAVI CENU I NAZIV ZA PROIZVOD
				case POSTAVI_NAZIV_CENU:{
					if(broj_poruke==1){
						broj_proizvoda = poruka;
						broj_poruke++;
					}else if(broj_poruke>=2 && broj_poruke<18){
						nazivi_proizvoda[broj_proizvoda][broj_poruke-2]=poruka;
						broj_poruke++;
					}else if (broj_poruke == 18){
						cene_proizvoda[broj_proizvoda]=poruka;
						broj_poruke++;
					}
					else {
						short temp = poruka<<8;
						cene_proizvoda[broj_proizvoda] += temp;
						trenutno_stanje = STARTNO_STANJE;
						broj_poruke = 0;
					}
				}break;
				//PROMENI CENU PROIZVODU
				case POSTAVI_CENU:{
					if(broj_poruke==1){
						broj_proizvoda = poruka;
						broj_poruke++;
					}else{
						cene_proizvoda[broj_proizvoda]=poruka;
						trenutno_stanje = STARTNO_STANJE;
						broj_poruke = 0;
					}
				}break;
				//RESETUJ ZARADU ZA PROIZVOD
				case RESETUJ_PROMET_P:{
					if(broj_poruke == 1){
						broj_proizvoda = poruka;
						cene_proizvoda[broj_proizvoda] = 0;
						trenutno_stanje = STARTNO_STANJE;
						broj_poruke = 0;
					 }
				}break;
				//SET TIME
				case PODESAVANJE_VREMENA:{
					msec = 0;
					if(broj_poruke == 1){
						sec = poruka;
						broj_poruke++;
					 }
					 else if(broj_poruke==2){
						min = poruka;
						broj_poruke++;
					 }
					 else{
						sati = poruka;
						trenutno_stanje = STARTNO_STANJE;
						vreme_podeseno = 1;
						broj_poruke=0;
					 }
				}break;
				//PROCITAJ PROMET ZA PROIZVOD
				case PROCITAJ_PROMET_P:{
					Lpromet = zarade_proizvoda[poruka] & 0x00FF;
					Hpromet = zarade_proizvoda[poruka] >> 8;
					SBUF=Lpromet;
				}break;				
			}
		}
		RI=0;
	}
	//TRANSMIT
	else if (TI == 1) {
		TI=0;		
		switch(trenutno_stanje){
			//PROCITAJ PROMET ZA JEDAN PROIZVOD/SVE PROIZVODE
			case PROCITAJ_PROMET_U:{
				SBUF=Hpromet;
				trenutno_stanje = STARTNO_STANJE;
				broj_poruke = 0;
			}break;
			case PROCITAJ_PROMET_P:{
				SBUF=Hpromet;
				trenutno_stanje = STARTNO_STANJE;
				broj_poruke = 0;
			}break;
		}
	}
}

